#include <iostream>
#include <vector>
#include <string>
#include <ClangFunction.h>
#include <WrapCodeGenerator.h>
#include <WrapCodeGeneratorOsg.h>
#include <RegCodeGenerator.h>
#include <RegCodeGeneratorOsg.h>
#include <cmdline.h>

#include <DefineCommon.h>

void testFileToCollection()
{
    CppInfo::CppFilePtr filePtr(new CppInfo::CppFile);
    filePtr->fileName = "data/clangTest/MatrixTransform.hpp";
    filePtr->classNameList.push_back("osg::MatrixTransform");
    filePtr->incFilePathList.push_back("./../Depend/osg/osg-3.7.0/install_vs2019_x64/include");

    CppInfo::CppCollectionPtr collPtr(new CppInfo::CppCollection);

    ClangFunction::fileToCollection(filePtr, collPtr);
    ELOG_INFO("collPtr=%s", collPtr->getPrintStr().data());
}

void testWrapCodeGenerator()
{
    std::vector<CppInfo::CppFilePtr> filePtrList; 
    EStringList fileNames;
    EStringList classNames;
    fileNames.push_back("data/clangTest/Object.hpp");
    fileNames.push_back("data/clangTest/Node.hpp");
    fileNames.push_back("data/clangTest/Group.hpp");
    fileNames.push_back("data/clangTest/Transform.hpp");
    fileNames.push_back("data/clangTest/MatrixTransform.hpp");
    fileNames.push_back("data/clangTest/Geode.hpp");
    fileNames.push_back("data/clangTest/Drawable.hpp");
    fileNames.push_back("data/clangTest/Geometry.hpp");
    fileNames.push_back("data/clangTest/AntiSquish.hpp");
             
    classNames.push_back("osg::Object");
    classNames.push_back("osg::Node");
    classNames.push_back("osg::Group");
    classNames.push_back("osg::Transform");
    classNames.push_back("osg::MatrixTransform");
    classNames.push_back("osg::Geode");
    classNames.push_back("osg::Drawable");
    classNames.push_back("osg::Geometry");
    classNames.push_back("osgManipulator::AntiSquish");
              

    for(int i = 0 ; i < fileNames.size(); i++)
    {
        CppInfo::CppFilePtr filePtr(new CppInfo::CppFile);
        filePtr->fileName = fileNames[i];
        filePtr->classNameList.push_back(classNames[i]);
        filePtr->incFilePathList.push_back("./../Depend/osg/osg-3.7.0/install_vs2019_x64/include");
        filePtrList.push_back(filePtr);
    }


    CppInfo::CppCollectionPtr collPtr(new CppInfo::CppCollection);

    for(int i = 0 ; i < filePtrList.size(); i++ )
    {
        ClangFunction::fileToCollection(filePtrList[i], collPtr);
    }
    // std::cout<<collPtr->toString().toStdString()<<std::endl;

    WrapCodeGeneratorPtr codeGenPtr(new WrapCodeGenerator);
    codeGenPtr->collectionToFiles(collPtr, "LibUiWrapOsg/");

    // RegCodeGeneratorPtr regCodePtr(new RegCodeGenerator);
    // regCodePtr->wrapClssListToFiles(codeGenPtr->m_wrapClassList, "LibUiWrapOsg/");
}

int main_simple(int argc, char *argv[])
{
    // spdlog::cfg::load_env_levels();
    // LOG_PRE_DEBUG;
    testWrapCodeGenerator();

    return 1;
}

/*TODO:this code is commited only for unuserable EFileInfo*/
// int modeFunReg( const EString& fileName, 
                // const EString& className, 
                // const EString& includePath,
                // const EString& outPutDir,
                // const EString& libName)
// {
    // //iterator includePath and find ItemWrap_xxx_gen.h files and fill class name string list.
    // QDir dir(includePath);
    // if(dir.exists() == false)
    // {
        // ELOG_ERROR("includePath is not existed");
        // return 1;
    // }

    // [>*find h file and fill classNameList<]
    // // LOG_INFO
    // QFileInfoList fileInfoList = dir.entryInfoList(QDir::Filter::Files);
    // EStringList classNameList;
    // for(int i = 0 ; i < fileInfoList.size(); i++)
    // {

        // if(fileInfoList[i].suffix() == "h" && fileInfoList[i].baseName().contains("RegFunction") == false)
        // {
            // // LOG_INFO(fileInfoList[i].baseName().toLocal8Bit().data());
            // classNameList.push_back(fileInfoList[i].baseName());
        // }
        // // fileInfoList[i].
    // }

    // if(libName == "osg")
    // {
        // RegCodeGeneratorOsgPtr regCodePtr(new RegCodeGeneratorOsg);
        // regCodePtr->wrapClssListToFiles(classNameList, 
                // outPutDir);
    // }

    // return 1;
// }

int modeFunWrap( const EString& fileName, 
                const EString& className, 
                const EString& includePath,
                const EString& outPutDir,
                const EString& libName)
{
    // ELOG_INFO("fileName={}", fileName.toLocal8Bit().data());
    // ELOG_INFO("className={}", className.toLocal8Bit().data());
    // ELOG_INFO("includePath={}", includePath.toLocal8Bit().data());
    // ELOG_INFO("outPutDir={}", outPutDir.toLocal8Bit().data());
    // ELOG_INFO("libName={}", libName.toLocal8Bit().data());

    std::vector<CppInfo::CppFilePtr> filePtrList; 
    EStringList fileNames;
    EStringList classNames;
    fileNames.push_back(fileName);
    classNames.push_back(className);

    EStringList includePathList = includePath.split(";");

    for(int i = 0 ; i < fileNames.size(); i++)
    {
        CppInfo::CppFilePtr filePtr(new CppInfo::CppFile);
        filePtr->fileName = fileNames[i];
        filePtr->classNameList.push_back(classNames[i]);
        filePtr->incFilePathList = includePathList;
        filePtrList.push_back(filePtr);
    }

    CppInfo::CppCollectionPtr collPtr(new CppInfo::CppCollection);

    for(int i = 0 ; i < filePtrList.size(); i++ )
    {
        ClangFunction::fileToCollection(filePtrList[i], collPtr);
    }
    // std::cout<<collPtr->toString().toStdString()<<std::endl;

    if(libName == "osg")
    {
        WrapCodeGeneratorOsgPtr codeGenPtr(new WrapCodeGeneratorOsg);
        codeGenPtr->collectionToFiles(collPtr, outPutDir);
    }
    return 1;
}

int main_old_version(int argc, char *argv[])//
{
    std::cout<<"hello world"<<std::endl;
    // spdlog::cfg::load_env_levels();
    ELOG_INFO("yyyyyyyyyyy");

    /*First modeName define wrap code code 
     * generating  or regFunction code generating  
     * for example:
     * -m "wrap osg", for wrap code
     * -m "reg osg", for reg code
     *
     * In wrap code mode,className is a single word.
     * In reg code mode,className is no meaning.
     * For example:
     * -c "osg::Node", for wrap code
     *
     * In wrap code mode, includePath is the dir needed by fileName.
     * In reg code mode, includePath is the ItemWrap_xxx_gen.h 's dir.
     * RegCodeGenerator will iterator the h file in includePath and generate RegFunctionXXX
     *
     */
    cmdline::parser cmdParser;
    cmdParser.add<std::string>("modeName", 
                                'm', 
                                "can be wrap or reg which defines wrap class generate mode, and then a space and follow a lib name, for example osg", 
                                true, 
                                "");
    cmdParser.add<std::string>("className", 
                                'c', 
                                "Class name in the head file", 
                                false, 
                                "");
    cmdParser.add<std::string>("outPutDir", 
                                'o', 
                                "The path to save wrap class code", 
                                true, 
                                "");
    cmdParser.add<std::string>("fileName", 
                                'f', 
                                "File name of C++ head file", 
                                false, 
                                "");
    cmdParser.add<std::string>("includePath", 
                                'i', 
                                "include path list need by head file, split with \";\"", 
                                false, 
                                "");

    cmdParser.parse_check(argc, argv);

    EString fileName = EString::fromStdString(cmdParser.get<std::string>("fileName"));
    EString className = EString::fromStdString(cmdParser.get<std::string>("className"));
    EString includePath = EString::fromStdString(cmdParser.get<std::string>("includePath"));
    EString outPutDir = EString::fromStdString(cmdParser.get<std::string>("outPutDir"));
    EString modeName = EString::fromStdString(cmdParser.get<std::string>("modeName"));
    
    
    EStringList modeStrList = modeName.split(" ");
    if(modeStrList.size() != 2)
    {
        ELOG_ERROR("modeName can not be splited into 2 words");
        return 0;
    }

    EString strMode = modeStrList[0];
    EString strLibName = modeStrList[1];

    if(strMode == "reg")
    {
        /*TODO:this code is commited only for unuserable EFileInfo*/
        // modeFunReg(fileName, 
                // className, 
                // includePath, 
                // outPutDir, 
                // strLibName);
    }
    else if(strMode == "wrap")
    {
        modeFunWrap(fileName, 
                className, 
                includePath, 
                outPutDir, 
                strLibName);
    }
    else 
    {
        ELOG_ERROR("The input mode string can not match reg or wrap"); 
    }



    // if (a.exist("gzip")) std::cout << "gzip" << std::endl;

    return 1;

}
